package com.lupengning.payment.controller;

import com.google.gson.Gson;
import com.lupengning.payment.service.OrderInfoService;
import com.lupengning.payment.service.WxPayService;
import com.lupengning.payment.util.HttpUtils;
import com.lupengning.payment.util.WechatPay2ValidatorForRequest;
import com.lupengning.payment.vo.R;
import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author lupengning
 * @version 1.0
 * @description:
 * @date 2021/12/28 9:21
 */
@Slf4j
@CrossOrigin
@RestController
@RequestMapping("/api/wx-pay")
@Api(tags = "网站微信支付API")
public class WxPayController {

  @Resource
  private WxPayService wxPayService;

  @Resource
  private OrderInfoService orderInfoService;

  @Resource
  private Verifier verifier;

  @ApiOperation("调用统一下单Api，生成支付二维码")
  @PostMapping("/native/{productId}")
  public R nativePay(@PathVariable Long productId) throws Exception {

    log.info("发起支付请求");

    Map<String, Object> map = wxPayService.nativePay(productId);
    return R.ok().setData(map);
  }

  /**
   * 支付通知 微信支付通过支付通知接口将用户支付成功消息通知给商户
   */
  @ApiOperation("支付通知")
  @PostMapping("/native/notify")
  public String nativeNotify(HttpServletRequest request, HttpServletResponse response) {
    Gson gson = new Gson();
    //应答对象
    Map<String, String> map = new HashMap<>();
    //处理通知参数
    try {
      String body = HttpUtils.readData(request);
      Map<String, Object> bodyMap = gson.fromJson(body, HashMap.class);
      log.info("支付通知的id ===> {}", bodyMap.get("id"));
      log.info("支付通知的完整数据 ===> {}", body);

      // 签名的验证
      WechatPay2ValidatorForRequest validator = new WechatPay2ValidatorForRequest(verifier, body,
          (String) bodyMap.get("id"));
      if (!validator.validate(request)) {
        log.error("通知验签失败");
        //应答失败
        response.setStatus(500);
        map.put("code", "ERROR");
        map.put("message", "失败");
        return gson.toJson(map);
      }
      log.info("通知验签成功");

      // 处理订单
      wxPayService.processOrder(bodyMap);

      // 应答超时测试
//        TimeUnit.SECONDS.sleep(5);

      //成功应答：成功应答必须为200或204，否则就是失败应答
      response.setStatus(200);
      map.put("code", "SUCCESS");
      map.put("message", "成功");
      return gson.toJson(map);
    } catch (Exception e) {
      e.printStackTrace();
      response.setStatus(500);
      map.put("code", "ERROR");
      map.put("message", "失败");
      return gson.toJson(map);
    }
  }

  /**
   * 用户取消订单
   *
   * @param orderNo
   * @return
   * @throws Exception
   */
  @ApiOperation("用户取消订单")
  @PostMapping("/cancel/{orderNo}")
  public R cancel(@PathVariable String orderNo) throws Exception {
    log.info("取消订单");
    wxPayService.cancelOrder(orderNo);
    return R.ok().setMessage("订单已取消");
  }

  /**
   * 查询订单
   *
   * @param orderNo
   * @return
   * @throws
   * @throws Exception
   */
  @ApiOperation("查询订单：测试订单状态用")
  @GetMapping("query/{orderNo}")
  public R queryOrder(@PathVariable String orderNo) throws Exception {
    log.info("查询订单");
    String bodyAsString = wxPayService.queryOrder(orderNo);
    return R.ok().setMessage("查询成功").data("bodyAsString", bodyAsString);
  }


  @ApiOperation("申请退款")
  @PostMapping("/refunds/{orderNo}/{reason}")
  public R refunds(@PathVariable String orderNo, @PathVariable String reason) throws Exception {
    log.info("申请退款");
    wxPayService.refund(orderNo, reason);
    return R.ok();
  }

  /**
   * 查询退款
   *
   * @param refundNo
   * @return
   * @throws Exception
   */
  @ApiOperation("查询退款：测试用")
  @GetMapping("/query-refund/{refundNo}")
  public R queryRefund(@PathVariable String refundNo) throws Exception {
    log.info("查询退款");
    String result = wxPayService.queryRefund(refundNo);
    return R.ok().setMessage("查询成功").data("result", result);
  }

  /**
   * 退款结果通知 退款状态改变后，微信会把相关退款结果发送给商户。
   */
  @PostMapping("/refunds/notify")
  public String refundsNotify(HttpServletRequest request, HttpServletResponse response) {
    log.info("退款通知执行");
    Gson gson = new Gson();
    Map<String, String> map = new HashMap<>();//应答对象
    try {
      //处理通知参数
      String body = HttpUtils.readData(request);
      Map<String, Object> bodyMap = gson.fromJson(body, HashMap.class);
      String requestId = (String) bodyMap.get("id");
      log.info("支付通知的id ===> {}", requestId);
//签名的验证
      WechatPay2ValidatorForRequest wechatPay2ValidatorForRequest = new WechatPay2ValidatorForRequest(
          verifier, requestId, body);
      if (!wechatPay2ValidatorForRequest.validate(request)) {
        log.error("通知验签失败");
//失败应答
        response.setStatus(500);
        map.put("code", "ERROR");
        map.put("message", "通知验签失败");
        return gson.toJson(map);
      }
      log.info("通知验签成功");
//处理退款单
      wxPayService.processRefund(bodyMap);
//成功应答
      response.setStatus(200);
      map.put("code", "SUCCESS");
      map.put("message", "成功");
      return gson.toJson(map);
    } catch (Exception e) {
      e.printStackTrace();
//失败应答
      response.setStatus(500);
      map.put("code", "ERROR");
      map.put("message", "失败");
      return gson.toJson(map);
    }
  }

  @ApiOperation("获取账单url：测试用")
  @GetMapping("/querybill/{billDate}/{type}")
  public R queryTradeBill(@PathVariable String billDate, @PathVariable String type) throws Exception {
    log.info("获取账单url");
    String downloadUrl = wxPayService.queryBill(billDate, type);
    return R.ok().setMessage("获取账单url成功").data("downloadUrl", downloadUrl);
  }

  @ApiOperation("下载账单")
  @GetMapping("/downloadbill/{billDate}/{type}")
  public R downloadBill(@PathVariable String billDate, @PathVariable String type) throws Exception {
    log.info("下载账单");
    String result = wxPayService.downloadBill(billDate, type);
    return R.ok().data("result", result);
  }


}
